home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / networking / amitcp / httpd.lha / httpd / http_script.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-18  |  10.3 KB  |  438 lines

  1. /*
  2.  * http_script: keeps all script-related ramblings together.
  3.  * 
  4.  * Compliant to CGI/1.0 spec
  5.  * 
  6.  * Rob McCool
  7.  *
  8.  */
  9.  
  10. #include "httpd.h"
  11.  
  12. #ifdef AMIGA
  13. #include <dos/dos.h>
  14. #include <dos/dostags.h>
  15. #endif
  16.  
  17. char **create_argv(char *av0, char *args) {
  18.     register int x,n;
  19.     char **av;
  20.     char w[MAX_STRING_LEN];
  21.     char l[MAX_STRING_LEN];
  22.  
  23.     for(x=0,n=2;args[x];x++)
  24.         if(args[x] == '+') ++n;
  25.  
  26.     av = (char **)malloc((n+1)*sizeof(char *));
  27.     av[0] = av0;
  28.     strcpy(l,args);
  29.     for(x=1;x<n;x++) {
  30.         getword(w,l,'+');
  31.         unescape_url(w);
  32.         av[x] = strdup(w);
  33.     }
  34.     av[n] = NULL;
  35.     return av;
  36. }
  37.  
  38. void get_path_info(char *path, char *path_args, FILE *out, 
  39.                    struct stat *finfo)
  40. {
  41.     register int n,x;
  42.     char t[MAX_STRING_LEN];
  43.  
  44.     path_args[0] = '\0';
  45.  
  46.     n=count_dirs(path);
  47.     for(x=0;x<=n;x++) {
  48.         make_dirstr(path,x+1,t);
  49.         if(!(stat(t,finfo))) {
  50.             if(S_ISREG(finfo->st_mode)) {
  51.                 strcpy(path_args,&path[strlen(t)]);
  52.                 strcpy(path,t);
  53.                 return;
  54.             }
  55.         }
  56.     }
  57.     unmunge_name(path);
  58.     die(NOT_FOUND,path,out);
  59. }
  60.  
  61. #ifndef NO_CGI_SCRIPTS
  62.  
  63. void exec_cgi_script(char *method, char *path, char *args, int in, FILE *out) 
  64. {
  65.     int pid, p[2];
  66.     int content, nph;
  67.     char cl[MAX_STRING_LEN],t[MAX_STRING_LEN],t2[MAX_STRING_LEN];
  68.     char path_args[MAX_STRING_LEN];
  69.     char *argv0;
  70.     FILE *psin;
  71.     struct stat finfo;
  72.  
  73.     get_path_info(path,path_args,out,&finfo);
  74.     
  75.     if(!can_exec(&finfo)) {
  76.         unmunge_name(path);
  77.         die(FORBIDDEN,path,out);
  78.     }
  79.  
  80.     /* BAD -- method specific */
  81.     evaluate_access(path,&finfo,((!strcmp(method,"POST")) ? M_POST : M_GET),
  82.                     &allow,&allow_options);
  83.     if(!allow) {
  84.         log_reason("client denied by server configuration",path);
  85.         unmunge_name(path);
  86.         die(FORBIDDEN,path,out);
  87.     }
  88.  
  89.     ht_putenv("SERVER_SOFTWARE",SERVER_VERSION);
  90.     ht_putenv("SERVER_NAME",server_hostname);
  91.     ht_putenv("GATEWAY_INTERFACE","CGI/1.0");
  92.  
  93.     sprintf(t,"%d",port);
  94.     ht_putenv("SERVER_PORT",t); /* we only listen to one port */
  95.  
  96.     ht_putenv("SERVER_PROTOCOL",(assbackwards ? "HTTP/0.9" : "HTTP/1.0"));
  97.     ht_putenv("REQUEST_METHOD",method);
  98.     ht_putenv("HTTP_ACCEPT",http_accept);
  99.     if(path_args[0]) {
  100.         ht_putenv("PATH_INFO",path_args);
  101.         strcpy(t2,path_args);
  102.         translate_name(t2,out);
  103.         ht_putenv("PATH_TRANSLATED",t2);
  104.     }
  105.     strcpy(t,path);
  106.     unmunge_name(t);
  107.     ht_putenv("SCRIPT_NAME",t);
  108.     ht_putenv("QUERY_STRING",args);
  109.     ht_putenv("REMOTE_HOST",remote_name);
  110.     ht_putenv("REMOTE_ADDR",remote_ip);
  111.     if(user[0])
  112.         ht_putenv("REMOTE_USER",user);
  113.     if(auth_type)
  114.         ht_putenv("AUTH_TYPE",auth_type);
  115.  
  116.     content=0;
  117.     if((!strcmp(method,"POST")) || (!strcmp(method,"PUT"))) {
  118.         content=1;
  119.         sprintf(cl,"%d",content_length);
  120.         ht_putenv("CONTENT_TYPE",content_type);
  121.         ht_putenv("CONTENT_LENGTH",cl);
  122.     }
  123.  
  124.     if((argv0 = strrchr(path,'/')) != NULL)
  125.         argv0++;
  126.     else argv0 = path;
  127.  
  128. #ifndef AMIGA
  129.     if(pipe(p) < 0)
  130.         die(SERVER_ERROR,"httpd: could not create IPC pipe",out);
  131.     if((pid = fork()) < 0)
  132.         die(SERVER_ERROR,"httpd: could not fork new process",out);
  133.  
  134.     nph = (strncmp(argv0,"nph-",4) ? 0 : 1);
  135.     if(!pid) {
  136.         if(content)
  137.             if(in != STDIN_FILENO) {
  138.                 dup2(in,STDIN_FILENO);
  139.                 close(in);
  140.             }
  141.         if(nph) {
  142.             if(fileno(out) != STDOUT_FILENO) {
  143.                 dup2(fileno(out),STDOUT_FILENO);
  144.                 dup2(fileno(out),STDERR_FILENO);
  145.                 fclose(out);
  146.             }
  147.         } else {
  148.             if(p[1] != STDOUT_FILENO) {
  149.                 dup2(p[1],STDOUT_FILENO);
  150.                 close(p[1]);
  151.             }
  152.         }
  153.         dup2(STDOUT_FILENO,STDERR_FILENO);
  154.         /* Only ISINDEX scripts get decoded arguments. */
  155.         if((!args[0]) || (ind(args,'=') >= 0)) {
  156.             if(execl(path,argv0,(char *)0) == -1)
  157.                 exit(1);
  158.         }
  159.         else
  160.             if(execv(path,create_argv(argv0,args)) == -1)
  161.                 exit(1);
  162.     }
  163.     else
  164.         close(p[1]);
  165. #else
  166.     nph = 0;    /* Not yet supported */
  167.  
  168.     {
  169.         ULONG ChildIn;
  170.         ULONG ChildOut;
  171.         char buffer[256];
  172.         char * invoker = "";
  173.  
  174.     if( can_script( &finfo ) )
  175.         invoker = "execute";
  176.     else
  177.     {
  178.         FILE * fh;
  179.  
  180.         if( fh = fopen( path, "r" ) )
  181.         {
  182.             fread( buffer, 3, 1, fh );
  183.             fclose( fh );
  184.  
  185.             if( (buffer[0] == '/' ) && (buffer[1] == '*' ) )
  186.                 invoker = "rx";
  187.         }
  188.     }
  189.  
  190.     sprintf( buffer, "%s %s %s", invoker, path, args );
  191.  
  192.     ChildIn  = Open( "nil:", MODE_OLDFILE );
  193.     ChildOut = Open( "pipe:http-cgi", MODE_NEWFILE );
  194.  
  195.     if( ChildIn && ChildOut
  196.      && ( SystemTags( buffer, SYS_Asynch, TRUE,
  197.                       SYS_Input, ChildIn,
  198.                       SYS_Output, ChildOut,
  199.                       TAG_DONE ) >= 0 ) )
  200.     {
  201.     
  202.     }
  203.     else
  204.     {
  205.         if( ChildIn )  Close( ChildIn );
  206.         if( ChildOut ) Close( ChildOut );
  207.  
  208.  
  209.         die(SERVER_ERROR,"could not run script",out);
  210.     }
  211.  
  212.     }
  213.  
  214. #endif
  215.  
  216.     if(!nph) {
  217. #ifndef AMIGA
  218.         if(!(psin = fdopen(p[0],"r")))
  219. #else
  220.     if( ! (psin = fopen( "pipe:http-cgi", "r" ) ) )
  221. #endif
  222.             die(SERVER_ERROR,"could not read from script",out);
  223.  
  224.         if(scan_script_header(psin,out)) {
  225.             escape_url(location);
  226.             die(REDIRECT,location,out);
  227.         }
  228.  
  229.         if(location[0] == '/') {
  230.             char t[MAX_STRING_LEN];
  231.             fclose(psin);
  232.             strcpy(t,location);
  233.             location[0] = '\0';
  234.             process_get(in,out,method,t,NULL);
  235.             return;
  236.         }
  237.         content_length = -1;
  238.         if(!assbackwards)
  239.             send_mime_headers(out);
  240.  
  241.         send_fd(psin,out,args);
  242.         fclose(psin);
  243.     }
  244. #ifndef AMIGA
  245.     waitpid(pid,NULL,0);
  246. #endif
  247. }
  248.  
  249. #endif
  250.  
  251. void set_env_NCSA() {
  252.     char *t3;
  253.  
  254.     ht_putenv("DOCUMENT_ROOT",document_root);
  255.     ht_putenv("SERVER_ROOT",server_root);
  256.     ht_putenv("REMOTE_HOST",remote_name);
  257.     t3 = (char *)malloc(strlen("SERVER_NAME=") + strlen(server_hostname) + 6);
  258.     sprintf(t3,"SERVER_NAME=%s:%d",server_hostname,port);
  259.     putenv(t3);
  260. }
  261.  
  262. #ifndef NO_NCSA_EXEC
  263.  
  264. void exec_get_NCSA(char *path, char *args, FILE *fd) {
  265.     FILE *tfp;
  266.     struct stat finfo;
  267.     int pid,pfd[2];
  268.     char path_args[MAX_STRING_LEN];
  269.     char t[MAX_STRING_LEN];
  270.     register int n,x;
  271.  
  272.     set_env_NCSA();
  273.  
  274.     path_args[0] = '\0';
  275.     /* check if it's really a script with extra args */
  276.     n=count_dirs(path);
  277.     for(x=0;x<=n;x++) {
  278.         make_dirstr(path,x+1,t);
  279.         if(!(stat(t,&finfo))) {
  280.             if(S_ISREG(finfo.st_mode)) {
  281.                 strcpy(path_args,&path[strlen(t)]);
  282.                 strcpy(path,t);
  283.                 goto run_script;
  284.             }
  285.         }
  286.     }
  287.     log_reason("script not found or unable to stat",path);
  288.     unmunge_name(path);
  289.     die(NOT_FOUND,path,fd);
  290.   run_script:
  291.     if(!can_exec(&finfo)) {
  292.         log_reason("file permissions deny server execution",path);
  293.         unmunge_name(path);
  294.         die(FORBIDDEN,path,fd);
  295.     }
  296.     evaluate_access(path,&finfo,M_GET,&allow,&allow_options);
  297.     if(!allow) {
  298.         unmunge_name(path);
  299.         die(FORBIDDEN,path,fd);
  300.     }
  301.  
  302.     if(pipe(pfd) < 0)
  303.         die(SERVER_ERROR,"could not open pipe",fd);
  304.  
  305. #ifndef AMIGA
  306.     signal(SIGALRM,send_fd_timed_out);
  307.     signal(SIGPIPE,send_fd_timed_out);
  308. #endif
  309.     alarm(timeout);
  310.  
  311.     if((pid = fork()) < 0)
  312.         die(SERVER_ERROR,"could not fork",fd);
  313.     else if(!pid) {
  314.         char *argv0;
  315.  
  316.         close(pfd[0]);
  317.         if(pfd[1] != STDOUT_FILENO) {
  318.             dup2(pfd[1],STDOUT_FILENO);
  319.             close(pfd[1]);
  320.         }
  321.         if(argv0 = strrchr(path,'/'))
  322.             argv0++;
  323.         else
  324.             argv0 = path;
  325.         if(args[0] && path_args[0]) {
  326.             if(execl(path,argv0,path_args,args,(char *)0) == -1)
  327.                 exit(1);
  328.         }
  329.         else if(args[0]) {
  330.             if(execl(path,argv0,args,(char *)0) == -1)
  331.                 exit(1);
  332.         }
  333.         else if(path_args[0]) {
  334.             if(execl(path,argv0,path_args,(char *)0) == -1)
  335.                 exit(1);
  336.         }
  337.         else
  338.             if(execl(path,argv0,(char *)0) == -1)
  339.                 exit(1);
  340.     }
  341.     else
  342.         close(pfd[1]);
  343.  
  344.     tfp = fdopen(pfd[0],"r");
  345.  
  346.     if(scan_script_header(tfp,fd)) {
  347.         escape_url(location);
  348.         die(REDIRECT,location,fd);
  349.     }
  350.  
  351.     if(location[0] == '/') {
  352.         char *t = strdup(location);
  353.         location[0] = '\0';
  354.         send_node(t,"",fd);
  355.         exit(0);
  356.     }
  357.  
  358.     if(!assbackwards)
  359.         send_mime_headers(fd);
  360.  
  361.     if(!header_only)
  362.         send_fd(tfp,fd,args);
  363.     fclose(tfp);
  364.     waitpid(pid,NULL,0);
  365. }
  366.  
  367.  
  368.  
  369. void exec_post_NCSA(char *path, char *args, int in, FILE *out) {
  370.     int pid, inpipe[2],outpipe[2], x;
  371.     char cl[MAX_STRING_LEN];
  372.     FILE *psin,*psout;
  373.     struct stat finfo;
  374.     
  375.     set_env_NCSA();
  376.  
  377.     sprintf(cl,"%d",content_length);
  378.  
  379.     if(stat(path,&finfo) == -1) {
  380.         unmunge_name(path);
  381.         if(errno == ENOENT) die(NOT_FOUND,path,out);
  382.         die(FORBIDDEN,path,out);
  383.     }
  384.     evaluate_access(path,&finfo,M_POST,&allow,&allow_options);
  385.     if(!allow)
  386.         die(FORBIDDEN,path,out);
  387.  
  388.     if(pipe(inpipe) < 0)
  389.         die(SERVER_ERROR,"httpd: could not create IPC pipe",out);
  390.     if(pipe(outpipe) < 0)
  391.         die(SERVER_ERROR,"httpd: could not create IPC pipe",out);
  392.     if((pid = fork()) < 0)
  393.         die(SERVER_ERROR,"httpd: could not fork new process",out);
  394.  
  395.     if(!pid) {
  396.         char *argv0;
  397.  
  398.         if(outpipe[1] != STDOUT_FILENO) {
  399.             dup2(outpipe[1],STDOUT_FILENO);
  400.             close(outpipe[1]);
  401.         }
  402.         if(in != STDIN_FILENO) {
  403.             dup2(in,STDIN_FILENO);
  404.             close(in);
  405.         }
  406.         if((argv0 = strrchr(path,'/')) != NULL)
  407.             argv0++;
  408.         else argv0 = path;
  409.         if(execlp(path,argv0,cl,args,(char *)0) == -1)
  410.             exit(1);
  411.     }
  412.     else {
  413.         close(outpipe[1]);
  414.         close(inpipe[0]);
  415.     }
  416.  
  417.     if(!(psin = fdopen(outpipe[0],"r")))
  418.         die(SERVER_ERROR,"could not read from script",out);
  419.  
  420.     if(scan_script_header(psin,out)) {
  421.         escape_url(location);
  422.         die(REDIRECT,location,out);
  423.     }
  424.     content_length = -1;
  425.     if(!assbackwards) {
  426. /*        fstat(f,&finfo); */
  427. /*        set_content_length(finfo.st_size); */
  428. /*        set_last_modified(finfo.st_mtime); */
  429.         send_mime_headers(out);
  430.     }
  431.  
  432.     send_fd(psin,out,args);
  433.     fclose(psin);
  434.     waitpid(pid,NULL,0);
  435. }
  436.  
  437. #endif
  438.